package validation.jexp;

import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.value.ValueHolder;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * In addition to its superclass this class provides a bound
 * read-only property <em>composerEnabled</em> that is true
 * if and only if the underlying Album is non-{@code null} and classical.
 * This property is intended to be used by a variety of presentation properties,
 * not just a component's <em>enabled</em> state. You can enable or disable
 * a composer presentation, or switch a composer field's <em>editable</em>
 * property, or to hide and show a larger composer editor section.<p>
 *
 * I've added the <em>composerEnabled</em> property primarily for learning
 * and demonstration purposes. And I wanted to closely follow the example
 * used in Martin Fowler's description of the
 * <a href="http://martinfowler.com/eaaDev/PresentationModel.html">Presentation
 * Model</a> pattern. This example shows how "raw" domain object properties
 * can be aggregated or filtered by the presentation model layer for use in
 * the presentation layer. In cases where there's a direct mapping between
 * a raw property and the aggregated property used in the UI, it may be easier
 * to observe the raw property. But if this mapping becomes more complex
 * an aggregated property is recommended.<p>
 *
 * Note that a UI that buffers the classical property cannot use
 * <em>composerEnabled</em> but requires a separate aggregated property,
 * for example <em>bufferedComposerEnabled</em>. To keep this code close
 * to Fowler's original, I've implemented this feature in a subclass, see
 * {@link com.jgoodies.binding.tutorial.manager.BufferedAlbumPresentationModel}.
 * The buffered composer enabled property is an example where the eager
 * property aggregation adds overhead and complexity, and it may turn out
 * that using the buffered classical property would be easier to understand.
 *
 * @author  Karsten Lentzsch
 * @version $Revision: 1.14 $
 *
 * @see com.jgoodies.binding.tutorial.manager.BufferedAlbumPresentationModel
 */
public class AlbumPresentationModel extends PresentationModel<Album> {
    /**
     * The name of the bound read-only property that indicates that
     * a presentation for the composer property should be enabled/disabled,
     * editable/not editable, or visible/hidden.
     *
     * @see #isComposerEnabled()
     */
    public static final String PROPERTYNAME_COMPOSER_ENABLED = "composerEnabled";

    public AlbumPresentationModel(Album album) {
        super(new ValueHolder(album, true));
        initEventHandling();
    }

    /**
     * Registers a listener that is notified about changes in the
     * classical property of the current Album or a new Album.
     */
    private void initEventHandling() {
        getModel(Album.PROPERTY_CLASSICAL).addValueChangeListener(new ClassicalChangeHandler());
    }

    /**
     * Checks and answers if the underlying Album is non-{@code null}
     * and classical. This property is intended to be used with a variety
     * of presentation styles that indicate that a composer is absent
     * and cannot be edited. For example a presentations may choose
     * to switch the view's enablement or the editable state, or it
     * may hide or show a field or editor section.
     *
     * @return true if this model's current Album is non-{@code null}
     *     and classical.
     */
    public boolean isComposerEnabled() {
        return Boolean.TRUE.equals(getModel(Album.PROPERTY_CLASSICAL).getValue());
    }

    /**
     * Handles changes in the <em>classical</em> property.
     * Just notifies listeners about a change in the aggregated property
     * <em>composerEnabled</em>.
     */
    private final class ClassicalChangeHandler implements PropertyChangeListener {
        /**
         * The Album's classical property has changed. Notifies listeners
         * about a change in the "composerEnabled" property. Fires an event
         * that uses {@code null} as old value, and the current value
         * of this model's "composerEnabled" property as new value.
         *
         * @param evt    the event that describes the classical change
         */
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            firePropertyChange(PROPERTYNAME_COMPOSER_ENABLED, null, Boolean.valueOf(isComposerEnabled()));
        }
    }
}
